//
//	(c) 2009 Andrew Kalmacky
//
#include "dom_abstracts.h"

using namespace ak::dom;
using ak::string::string;

void report_unsupported_operation(const pin<Type>& type, const char_t* op_name)
{
	throw unsupported_operation_exception(string(T_("type "), type->get_printable_name(), T_(" does not support "), op_name));
}

template<typename T>
string get_printable_name(const T& n)
{
	string r = n.get_name();
	for (pin<T>& p = n.get_parent(); p; p = p->get_parent())
		r = string(p->get_name(), T_('.'), r);
	return r;
}

//
// -- TypeName ---------
//
TypeName::TypeName(const string& name)
	: name(name)
{
}

void TypeName::copy(Object*& dst) const
{
	dst = new TypeName(*this);
}

string TypeName::get_printable_name() const
{
	return ::get_printable_name<TypeName>(*this);
}

void TypeName::add_child(const pin<TypeName>& child)
{
	children[child->get_name()] = child;
	child->parent = this;
}

void TypeName::set_target(const pin<Type>& target)
{
	this->target = target;
}

pin<TypeName> TypeName::get_child(const string& name) const
{
	children_t::const_iterator i = children.find(name);
	return i == children.end() ? NULL : i->second;
}

pin<Type> TypeName::get_target() const
{
	return target;
}

name_iterator<TypeName> TypeName::get_children_iterator() const
{
	return name_iterator<TypeName>(this, children.begin());
}

pin<TypeName> TypeName::get_parent() const
{
	return parent;
}

pin<Type> TypeName::get_target_as_type() const
{
	if (!target && target->get_type_id() == TYPE_CLASS)
		throw unsupported_operation_exception(string(T_("name "), get_printable_name(), T_(" does not refer to type")));
	return target;
}
pin<Type> TypeName::get_target_as_class() const
{
	if (!target && target->get_type_id() != TYPE_CLASS)
		throw unsupported_operation_exception(string(T_("name "), get_printable_name(), T_(" does not refer to class")));
	return target;
}

//
// -- NodeName ---------
//
NodeName::NodeName(const pin<NodeName>& domain, const string& name, const pin<Node>& target)
	: name(name)
	, target(target)
	, parent(domain)
{
	if (domain)
		domain->children[name] = this;
}

void NodeName::copy(Object*& dst) const
{
	dst = copy_as_shared();
}

string NodeName::get_printable_name() const
{
	return ::get_printable_name<NodeName>(*this);
}

pin<NodeName> NodeName::get_child(const string& name) const
{
	children_t::const_iterator i = children.find(name);
	return i == children.end() ? pin<NodeName>() : i->second;
}

pin<Node> NodeName::get_target() const
{
	return target;
}

name_iterator<NodeName> NodeName::get_children_iterator() const
{
	return name_iterator<NodeName>(this, children.begin());
}

pin<NodeName> NodeName::get_parent() const
{
	return parent;
}

//
// -- Node -------------
//
Node::Node(const pin<Type>& type)
	: type(type)
{}
const_data Node::get_data() const
{
	return const_data(this, this, type);
}
data Node::get_data()
{
	return data(this, this, type);
}

//
// -- Field ---------
//
string Field::get_printable_name() const
{
	return string(type->get_printable_name(), T_(' '), name);
}

//
// -- EnumTag ---------
//
EnumTag::EnumTag(const string& name, size_t value)
	: name(name)
	, value(value)
{
}

string EnumTag::get_printable_name() const
{
	return name;
}

//
// -- Type ---------
//
string Type::get_printable_name() const
{
	if (pin<TypeName> n = name)
		return n->get_printable_name();
	else
		return T_("(null)");
}

bool Type::is_int_signed() const
{
	report_unsupported_operation(this, T_("is int signed"));
	return false;
}

size_t Type::get_enum_tags_count() const
{
	report_unsupported_operation(this, T_("get enum tags count"));
	return 0;
}

pin<EnumTag> Type::get_enum_tag(size_t index) const
{
	report_unsupported_operation(this, T_("get enum tag"));
	return NULL;
}

size_t Type::get_float_m_width() const
{
	report_unsupported_operation(this, T_("get float m width"));
	return 0;
}

size_t Type::get_float_p_width() const
{
	report_unsupported_operation(this, T_("get float p width"));
	return 0;
}

size_t Type::get_vector_static_items_count() const
{
	report_unsupported_operation(this, T_("get vector static items count"));
	return 0;
}

pin<Type> Type::get_vector_items_type() const
{
	report_unsupported_operation(this, T_("get vector items type"));
	return NULL;
}

size_t Type::get_struct_fields_count() const
{
	report_unsupported_operation(this, T_("get struct field count"));
	return 0;
}

pin<Field> Type::get_field(size_t field_index) const
{
	report_unsupported_operation(this, T_("get struct field"));
	return NULL;
}

pin<Field> Type::get_field(const string& name, const pin<Type> type, bool write_compatible) const
{
	report_unsupported_operation(this, T_("find struct field"));
	return NULL;
}

bool Type::check_if_contains(const pin<Field>& field) const
{
	return false;
}

size_t Type::get_instance_size() const
{
	report_unsupported_operation(this, T_("instance size"));
	return 0;
}

void Type::construct(void* ptr) const
{
	report_unsupported_operation(this, T_("construct"));
}

void Type::destruct(void* ptr) const
{
	report_unsupported_operation(this, T_("destruct"));
}

void Type::copy(void* dst_ptr, void* src_ptr) const
{
	report_unsupported_operation(this, T_("copy"));
}

pin<Node> Type::make_instance() const
{
	report_unsupported_operation(this, T_("make_instance"));
	return NULL;
}

int Type::read_int(void* ptr) const
{
	report_unsupported_operation(this, T_("read int"));
	return 0;
}

long64 Type::read_long64(void* ptr) const
{
	report_unsupported_operation(this, T_("read long64"));
	return 0;
}

double Type::read_double(void* ptr) const
{
	report_unsupported_operation(this, T_("read double"));
	return 0;
}

pin<EnumTag> Type::read_tag(void* ptr) const
{
	report_unsupported_operation(this, T_("read tag"));
	return NULL;
}

string Type::read_string(void* ptr) const
{
	report_unsupported_operation(this, T_("read string"));
	return string();
}

pin<Node> Type::read_ptr(void* ptr) const
{
	report_unsupported_operation(this, T_("read ptr"));
	return NULL;
}

size_t Type::read_items_count(void* ptr) const
{
	report_unsupported_operation(this, T_("read items count"));
	return 0;
}

void* Type::read_item_offset(void* ptr, size_t index) const
{
	report_unsupported_operation(this, T_("read item offset"));
	return NULL;
}

void Type::write_int(void* ptr, int val) const
{
	report_unsupported_operation(this, T_("write int"));
}

void Type::write_long64(void* ptr, long64 val) const
{
	report_unsupported_operation(this, T_("write long64"));
}

void Type::write_double(void* ptr, double val) const
{
	report_unsupported_operation(this, T_("write double"));
}

void Type::write_tag(void* ptr, const pin<EnumTag>& val) const
{
	report_unsupported_operation(this, T_("write tag"));
}

void Type::write_string(void* ptr, const string& val) const
{
	report_unsupported_operation(this, T_("write string"));
}

void Type::write_ptr(void* ptr, const pin<Node>& val) const
{
	report_unsupported_operation(this, T_("write ptr"));
}

void Type::insert_items(void* ptr, size_t index, size_t count) const
{
	report_unsupported_operation(this, T_("insert items"));
}

void Type::delete_items(void* ptr, size_t index, size_t count) const
{
	report_unsupported_operation(this, T_("delete items"));
}

size_t Type::get_instance_fields_count(void* ptr) const
{
	return 0;
}

void Type::update_instance_version(void* ptr) const
{
}
